package jeconbond.economic.market.strategy;

import jeconbond.economic.production.IResourceNecessityInformer;
import jeconbond.economic.resources.IResourceType;
import jeconbond.economic.resources.ResourceBasket;
import jeconbond.economic.resources.ResourceStorrage;
import jeconbond.economic.resources.ResourceUtils;
import jeconbond.economic.systems.market.IMarketResourceRedestributionSystem;
import jeconbond.economic.systems.market.IMoneyAccount;
import jeconbond.economic.systems.market.ISellProposition;
import jeconbond.economic.systems.market.SellProposition;
import jeconbond.economic.strategy.IMerchant;

import java.util.List;

public class ProductNecessityMerchant implements IMerchant, IProcessDealStrategy {
	private IMarketResourceRedestributionSystem mrrs;
	private IMoneyAccount money;
	private ResourceStorrage inputRS;
	private ResourceStorrage outputRS;

	private IProcessDealStrategy processDealStrategy = this;
	private IPerformPriceStrategy performPriceStrategy = null;

	private IResourceNecessityInformer informer;
	private double purchaseLevel;
	
	public ProductNecessityMerchant(
			IMarketResourceRedestributionSystem mrrs,
			IMoneyAccount money,
			ResourceStorrage inputRS,
			ResourceStorrage outputRS,
			IResourceNecessityInformer informer,
			double purchaseLevel
	) {
		this.mrrs = mrrs;
		this.money = money;
		this.inputRS = inputRS;
		this.outputRS = outputRS;
		this.informer = informer;
		this.purchaseLevel = purchaseLevel;
	}

	@Override
	public void processPurchase() {
		List<IResourceNecessityInformer.InfoItem> infoItemsList = informer.listInfoItems();
		for (IResourceNecessityInformer.InfoItem item : infoItemsList) {
			receiveNecessaryValue(item, purchaseLevel);
		}
	}

	@Override
	public void processSelling() {
		for (ResourceBasket rb : outputRS.listBaskets()) {
			if (rb.value > 0.0) {
				double price = performPriceStrategy.performPrice(rb.type);
				ISellProposition prop = new SellProposition(
						rb.type,
						price,
						outputRS,
						money
				);
				mrrs.registerProposition(prop);
			}
		}
	}

	@Override
	public void setProcessDealStrategy(IProcessDealStrategy processDealStrategy) {
		this.processDealStrategy = processDealStrategy;
	}

	@Override
	public IMoneyAccount getMoneyAccount() {
		return money;
	}

	// IProcessDealStrategy
	@Override
	public void processDeal(ISellProposition sellProposition, double value) {
		ResourceUtils.processDeal(sellProposition, value, money, inputRS, mrrs);
	}

	public void setPerformPriceStrategy(IPerformPriceStrategy performPriceStrategy) {
		this.performPriceStrategy = performPriceStrategy;
	}
	
	private void receiveNecessaryValue(
			IResourceNecessityInformer.InfoItem item,
			double purchaseLevel
	) {
		IResourceType type = item.basket.type;
		double valn = getNecessaryValue(item, purchaseLevel);
		ISellProposition[] props = mrrs.getSellPropositionsList(item.basket.type);
		ResourceUtils.sortSellPropositions(props);
		for (ISellProposition sp : props) {
			if (valn == 0.0) {
				break;
			}
			double val = Math.min(
					valn,
					sp.getSellerStorrage().howMuchWasStored(type)
					);
			double price = val * sp.getPrice();
			if (price <= money.getBalance()) {
				processDealStrategy.processDeal(sp, val);
				valn -= val;
			}
		}
	}

	private double getNecessaryValue(
			IResourceNecessityInformer.InfoItem item,
			double purchaseLevel
	) {
		if (item.proirityLevel < purchaseLevel) {
			double avail = inputRS.howMuchWasStored(item.basket.type);
			return Math.max(0.0, item.basket.value - avail);
		} else {
			return 0.0;
		}
	}
}
